﻿// ....................................................................................................................
//	Author: Copyright (C) 2012 Ing. Marek Hubal
//	Email: hubal@acasoftware.org
// ....................................................................................................................

using System;

namespace core
{
    /// <summary>Trieda INodeList_TAR</summary>
    public class INodeList_TAR : INodeList
    {

        /// <summary>Trieda INodeComparer</summary>
        protected class INodeComparer : System.Collections.Generic.IComparer<INode>
        {
            protected delegate int OnCompare(INode N1, INode N2);
            protected OnCompare FCompareMethod; // Metoda porovnania

            /// <summary>Porovnanie podla nazvu asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_0_Asc(INode N1, INode N2)
            {
                return string.Compare(((INodeData_TAR_ITEM)N1.NodeData).TAR_ItemName, ((INodeData_TAR_ITEM)N2.NodeData).TAR_ItemName);
            }
            /// <summary>Porovnanie podla nazvu desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_0_Desc(INode N1, INode N2)
            {
                return -string.Compare(((INodeData_TAR_ITEM)N1.NodeData).TAR_ItemName, ((INodeData_TAR_ITEM)N2.NodeData).TAR_ItemName);
            }
            /// <summary>Porovnanie podla pripony asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_1_Asc(INode N1, INode N2)
            {
                int R = string.Compare(N1.Ext, N2.Ext);
                if (R == 0) return Compare_0_Asc(N1, N2);
                else return R;
            }
            /// <summary>Porovnanie podla pripony desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_1_Desc(INode N1, INode N2)
            {
                int R = -string.Compare(N1.Ext, N2.Ext);
                if (R == 0) return Compare_0_Desc(N1, N2);
                else return R;
            }
            /// <summary>Porovnanie podla velkosti asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_2_Asc(INode N1, INode N2)
            {
                if (N1.Size == N2.Size) return Compare_0_Asc(N1, N2);
                return N1.Size > N2.Size ? 1 : -1;
            }
            /// <summary>Porovnanie podla velkosti desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_2_Desc(INode N1, INode N2)
            {
                if (N1.Size == N2.Size) return Compare_0_Desc(N1, N2);
                return N1.Size > N2.Size ? -1 : 1;
            }
            /// <summary>Porovnanie podla datumu posledneho zapisu asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_3_Asc(INode N1, INode N2)
            {
                int R = N1.DLastModify.CompareTo(N2.DLastModify);
                if (R == 0) return Compare_0_Asc(N1, N2);
                return R;
            }
            /// <summary>Porovnanie podla datumu posledneho zapisu desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_3_Desc(INode N1, INode N2)
            {
                int R = -N1.DLastModify.CompareTo(N2.DLastModify); ;
                if (R == 0) return Compare_0_Desc(N1, N2);
                return R;
            }

            /// <summary>Konstruktor</summary>
            /// <param name="pCol">triediaci stlpec</param>
            /// <param name="pDirection">smer</param>
            public INodeComparer(int pCol, bool pDirection)
            {
                switch (pCol)
                {
                    case 3: if (pDirection) FCompareMethod = Compare_3_Asc; else FCompareMethod = Compare_3_Desc; break;
                    case 2: if (pDirection) FCompareMethod = Compare_2_Asc; else FCompareMethod = Compare_2_Desc; break;
                    case 1: if (pDirection) FCompareMethod = Compare_1_Asc; else FCompareMethod = Compare_1_Desc; break;
                    default: if (pDirection) FCompareMethod = Compare_0_Asc; else FCompareMethod = Compare_0_Desc; break;
                }
            }

            /// <summary>Compare metoda</summary>
            /// <param name="x">objekt 1</param>
            /// <param name="y">objekt 2</param>
            /// <returns>vysledok porovnania</returns>
            int System.Collections.Generic.IComparer<INode>.Compare(INode x, INode y)
            {
                return FCompareMethod(x, y); // Volam porovnavaciu metodu
            }
        }

        protected string FBaseArchiveFileName; // Nazov archivu
        protected string FRelativePath; // Relativna cesta

        protected bool FExpand_Expanded; // Priznak vykonania extrahovania node zo suboru
        protected System.IO.BinaryReader FExpand_ArchiveFile; // Stream pre pracu v extract mode
        protected byte[] FExpand_Buffer; // Buffer pre expand
        protected long FExpand_CurrentPosition; // Pozicia streamu pre expand
        protected System.Collections.Generic.List<INode> FExpand_Dirs;
        protected System.Collections.Generic.List<INode> FExpand_Files;
        protected long FExpand_CurrentFilePosition; // Aktualna pozicia v subore pri expandovani
        protected int FExpand_TotalCount; // Pocitadlo vsetkych poloziek pri expande

        protected System.IO.BinaryReader FExtract_ArchiveFile; // Stream pre pracu v extract mode
        protected INode FExtract_CurrentItem; // Node pre aktualne spracovany zaznam
        protected long FExtract_CurrentItemReaded; // Pocet bajtov citanych z aktualnej polozky
        protected int FExtract_SkipBytesCount; // Pocet bajtov na preskocenie aby sa nastavil kurzor na novy zaznam
        protected System.Collections.Generic.List<string> FExtract_ListOfItems; // Zoznam poloziek na extrahovanie
        protected string FExtract_ListOfItemsRoot; // Spolocny zaciatok vsetkych poloziek

        public string ArchiveTypeString; // Typ archivu

        /// <summary>Property: CacheID</summary>
        public override string CacheID
        {
            get
            {
                return FBaseArchiveFileName.ToLower(); ;
            }
        }

        /// <summary>Konstruktor</summary>
        /// <param name="pArchiveFileName">nazov suboru archivu</param>
        /// <param name="pRelativePath">relativna cesta v archive</param>
        public INodeList_TAR(string pArchiveFileName = "", string pRelativePath = "")
        {
            ID = INodeList.NODE_LIST_ID_TAR_ARCHIVE;
            FColsCount = 7;
            FEnableVisibilityMask = 0x7e; FDefVisibilityMask = 0x7f;
            FThreadExpandAvailable = true;
            FBaseArchiveFileName = pArchiveFileName; FRelativePath = pRelativePath;
            ArchiveTypeString = "TAR";
        }

        /// <summary>Zapis node do cache</summary>
        /// <param name="pNode">objekt</param>
        protected override void WriteNodeToCache(INode pNode)
        {
            if (!IsWriteCacheReady) return; // Ziadna cache?

            FCacheWriter.Write(pNode.ID);
            FCacheWriter.Write(((INodeData_TAR_ITEM)pNode.NodeData).TAR_FileMode);
            FCacheWriter.Write(((INodeData_TAR_ITEM)pNode.NodeData).TAR_GroupID);
            FCacheWriter.Write(((INodeData_TAR_ITEM)pNode.NodeData).TAR_IsDirectory);
            FCacheWriter.Write(((INodeData_TAR_ITEM)pNode.NodeData).TAR_ItemName);
            FCacheWriter.Write(((INodeData_TAR_ITEM)pNode.NodeData).TAR_ModifyDate);
            FCacheWriter.Write(((INodeData_TAR_ITEM)pNode.NodeData).TAR_OriginalSize);
            FCacheWriter.Write(((INodeData_TAR_ITEM)pNode.NodeData).TAR_UserID);
            FCacheWriter.Write(((INodeData_TAR_ITEM)pNode.NodeData).TAR_DataPosition);
        }
        /// <summary>Nacitanie node z cache</summary>
        /// <returns>objekt alebo null pre koniec</returns>
        protected override bool ReadNodeFromCache(INode Result)
        {
            if (!IsReadCacheReady) return false;
            try
            {
                Result.ID = FCacheReader.ReadInt32(); // Nacitam
                Result.NodeData = new INodeData_TAR_ITEM();
                ((INodeData_TAR_ITEM)Result.NodeData).TAR_FileMode = FCacheReader.ReadUInt32();
                ((INodeData_TAR_ITEM)Result.NodeData).TAR_GroupID = FCacheReader.ReadString();
                ((INodeData_TAR_ITEM)Result.NodeData).TAR_IsDirectory = FCacheReader.ReadBoolean();
                ((INodeData_TAR_ITEM)Result.NodeData).TAR_ItemName = FCacheReader.ReadString();
                ((INodeData_TAR_ITEM)Result.NodeData).TAR_ModifyDate = FCacheReader.ReadUInt32();
                ((INodeData_TAR_ITEM)Result.NodeData).TAR_OriginalSize = FCacheReader.ReadInt64();
                ((INodeData_TAR_ITEM)Result.NodeData).TAR_UserID = FCacheReader.ReadString();
                ((INodeData_TAR_ITEM)Result.NodeData).TAR_DataPosition = FCacheReader.ReadInt64();
                return true; // Vsetko OK
            }
            catch
            {
                return false;
            }
        }
        /// <summary>Otvorenie cache pre citanie</summary>
        /// <returns>true / false</returns>
        public override bool BeginReadCache()
        {
            return false;
        }

        /// <summary>Nacitanie bufra pri expandovani</summary>
        protected virtual void Expand_ReadBuffer()
        {
            FExpand_ArchiveFile.Read(FExpand_Buffer, 0, 512);
            FExpand_CurrentFilePosition += 512;
        }
        /// <summary>Preskocenie bytov pri expandovani</summary>
        /// <param name="pCount">pocet</param>
        protected virtual void Expand_SkipBytes(long pCount)
        {
            if (FExpand_ArchiveFile.BaseStream.Position + pCount > FExpand_ArchiveFile.BaseStream.Length) throw(new System.IO.EndOfStreamException());
            FExpand_ArchiveFile.BaseStream.Position += pCount;
            FExpand_CurrentFilePosition += pCount;
        }
        /// <summary>Preskocenie bytov v streame</summary>
        /// <param name="pStream">stream</param>
        /// <param name="pCount">pocet</param>
        protected virtual void SkipBytesInStream(System.IO.BinaryReader pStream, long pCount)
        {
            pStream.BaseStream.Position += pCount;
        }
        /// <summary>Otvorenie streamu pre testovanie</summary>
        /// <param name="pFileName">nazov suboru</param>
        /// <returns>stream</returns>
        protected virtual System.IO.BinaryReader TestArchive_OpenStream(string pFileName)
        {
            return new System.IO.BinaryReader(System.IO.File.OpenRead(pFileName));
        }

        /// <summary>Ziskanie nazvu stlpca</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>nazov alebo prazdny retazec</returns>
        public override string GetColumnName(int pIndex)
        {
            switch (pIndex)
            {
                case 0: return lang.NODE_LIST_TAR_ARCHIVE_TEXT_1;
                case 1: return lang.NODE_LIST_TAR_ARCHIVE_TEXT_2;
                case 2: return lang.NODE_LIST_TAR_ARCHIVE_TEXT_3;
                case 3: return lang.NODE_LIST_TAR_ARCHIVE_TEXT_4;
                case 4: return lang.NODE_LIST_TAR_ARCHIVE_TEXT_5;
                case 5: return lang.NODE_LIST_TAR_ARCHIVE_TEXT_6;
                case 6: return lang.NODE_LIST_TAR_ARCHIVE_TEXT_7;
                default: return "";
            }
        }
        /// <summary>Ziskanie zarovnania stlpca</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>zarovnanie</returns>
        public override System.Windows.Forms.HorizontalAlignment GetColumnAlignment(int pIndex)
        {
            switch (pIndex)
            {
                case 2:
                    return System.Windows.Forms.HorizontalAlignment.Right;
                case 3:
                case 4:
                case 5:
                case 6:
                    return System.Windows.Forms.HorizontalAlignment.Center;
                default: return System.Windows.Forms.HorizontalAlignment.Left;
            }
        }
        /// <summary>Property: CurrentPath</summary>
        public override string CurrentPath
        {
            get
            {
                return IFileSystem.CreateFullArchivePath(FBaseArchiveFileName, FRelativePath);
            }
        }
        /// <summary>Property: KeyValue</summary>
        public override string KeyValue
        {
            get
            {
                if (FRelativePath == "") return IFileSystem.ExtractName(FBaseArchiveFileName).ToLower();
                return IFileSystem.ExtractName(IFileSystem.CreateFullArchivePath(FBaseArchiveFileName, FRelativePath)).ToLower();
            }
        }
        /// <summary>Test ci sa node moze expandovat</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanNodeExpand(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return false; // Ziskam platny node

            switch (N.ID)
            {
                case INode.NODE_ID_TAR_ITEM:
                    {
                        return ((INodeData_TAR_ITEM)N.NodeData).TAR_IsDirectory;
                    }
                default: return false;
            }
        }
        /// <summary>Ziskanie expandovacej cesty node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>cesta</returns>
        public override string GetNodeExpandPath(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return ""; // Ziskam platny node

            switch (N.ID)
            {
                case INode.NODE_ID_TAR_ITEM: return IFileSystem.AppendToPath(IFileSystem.CreateFullArchivePath(FBaseArchiveFileName, FRelativePath), ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName);
                default: return "";
            }
        }
        /// <summary>Property: CurrentPath</summary>
        public override string ParentPath
        {
            get
            {
                if (FRelativePath == "") return IFileSystem.ExtractPath(FBaseArchiveFileName);
                int I = FRelativePath.LastIndexOf('\\');
                if (I == -1) return FBaseArchiveFileName;
                return IFileSystem.CreateFullArchivePath(FBaseArchiveFileName, FRelativePath.Substring(0, I));
            }
        }
        /// <summary>Property: CanSelect</summary>
        public override bool CanSelect
        {
            get
            {
                return true;
            }
        }
        /// <summary>Test moznosti oznacenia node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        /// <summary>Test moznosti oznacenia node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanSelectNode(INode pNode)
        {
            if (pNode == null) return false; // Ziskam platny node

            switch (pNode.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }
        /// <summary>Property: CanSort</summary>
        public override bool CanSort
        {
            get
            {
                return true;
            }
        }
        /// <summary>Test ci je mozne podla zadaneho stlpca triedit</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool IsSortColumn(int pIndex)
        {
            switch (pIndex)
            {
                case 4:
                case 5:
                case 6:
                    return false;
                default: return true;
            }
        }
        /// <summary>Property: DeviceRootPath</summary>
        public override string DeviceRootPath
        {
            get
            {
                return FBaseArchiveFileName;
            }
        }
        /// <summary>Property: Test ci je list archivom</summary>
        public override bool IsArchive
        {
            get
            {
                return true;
            }
        }
        /// <summary>Property: ArchiveName</summary>
        public override string ArchiveName
        {
            get
            {
                return FBaseArchiveFileName;
            }
        }
        /// <summary>Property: IsCopySource</summary>
        public override bool IsCopySource
        {
            get
            {
                return true;
            }
        }
        /// <summary>Property: IsCopySourceItem</summary>
        public override bool IsCopySourceItem(int pIndex)
        {
            if (!IsCopySource) return false; // Test celku
            INode N = this[pIndex];
            if (N == null) return false; // Neplatny node?
            switch (N.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }
        /// <summary>Property: BasePath</summary>
        public override string BasePath
        {
            get
            {
                return FBaseArchiveFileName;
            }
        }

        /// <summary>Zaciatok expandovania obsahu</summary>
        /// <param name="pFilter">objekt filtra</param>
        /// <returns>0 alebo kod chyby</returns>
        public override int BeginExpand(INodeFilters pFilter = null)
        {
            FState = 1; // Nastavim stav expandovania
            try
            {
                FExpand_ArchiveFile = new System.IO.BinaryReader(System.IO.File.OpenRead(FBaseArchiveFileName)); // Otvorim stream archivu
                FExpand_Buffer = new byte[512]; FExpand_CurrentPosition = 0;
                FExpand_Dirs = new System.Collections.Generic.List<INode>(); FExpand_Files = new System.Collections.Generic.List<INode>();
                FExpand_CurrentFilePosition = 0; FExpand_TotalCount = 0;
            }
            catch
            {
                return -1; // Nie je mozne otvorit archiv
            }

            FExpand_Expanded = false;
            return 0;
        }
        /// <summary>Uzatvorenie aktualneho expandu</summary>
        public override void CloseExpand()
        {
            FExpand_ArchiveFile = (System.IO.BinaryReader)ICore.DisposeObject(FExpand_ArchiveFile); // Zrusim stream
            FExpand_Buffer = null;

            for (int i = 0; i < FExpand_Dirs.Count; i++) AddNode(FExpand_Dirs[i]);
            for (int i = 0; i < FExpand_Files.Count; i++) AddNode(FExpand_Files[i]);

            FExpand_Dirs.Clear(); FExpand_Dirs = null;
            FExpand_Files.Clear(); FExpand_Files = null;
            
            FState = 0; // Nastavim normalny stav
        }
        /// <summary>Expandovanie dalsieho zaznamu</summary>
        /// <param name="Result">ulozeny obsah najdeneho zaznamu alebo null ak sa ma zaznam pripojit do zoznamu</param>
        /// <returns>0 - ziaden dalsi zaznam, 1 - najdeny zaznam alebo kod chyby</returns>
        public override int ExpandNext(INodeFilters pFilter = null, INode Result = null)
        {
            if (!FExpand_Expanded)
            {
                if (Result == null)
                {
                    INode N2 = new INode(); N2.ID = INode.NODE_ID_BACK_ITEM; AddNode(N2); // Vytvorim prvy back item node
                }
                FExpand_Expanded = true;
            }

            try
            {
                string P1 = FRelativePath.Replace('\\', '/') + "/";
                while (true)
                {
                    if (IsReadCacheReady)
                    {
                        INode N = Result == null ? new INode() : Result;
                        if (!ReadNodeFromCache(N)) return 0;
                        WriteNodeToCache(N);

                        FExpand_TotalCount++;
                        if (!IsItemInCurrentLevel(P1, ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName))
                        {
                            if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_TAR_ARCHIVE_TEXT_14, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                            continue;
                        }
                        int I = ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName.LastIndexOf('/');
                        if (I != -1) ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName = ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName.Substring(I + 1); // Ziskam nazov bez cesty

                        if (Result == null)
                        {
                            if (((INodeData_TAR_ITEM)N.NodeData).TAR_IsDirectory) FExpand_Dirs.Add(N); else FExpand_Files.Add(N);
                            if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_TAR_ARCHIVE_TEXT_14, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                        }
                        FCachedContent = true;
                    }
                    else
                    {
                        Expand_ReadBuffer(); // Citam buffer
                        if (FExpand_Buffer[0] == 0) return 0; // Koniec?

                        INode N = Result == null ? new INode() : Result;
                        N.ID = INode.NODE_ID_TAR_ITEM;
                        N.NodeData = new INodeData_TAR_ITEM();

                        System.Text.Encoding E = System.Text.Encoding.Default; // Nastavim kodovanie

                        System.Text.StringBuilder B = new System.Text.StringBuilder();
                        int i;
                        for (i = 0; i < 100; i++) // Citam nazov
                        {
                            if (FExpand_Buffer[i] == 0) break;
                        }
                        B.Append(E.GetString(FExpand_Buffer, 0, i));
                        ((INodeData_TAR_ITEM)N.NodeData).TAR_IsDirectory = B[B.Length - 1] == '/';
                        if (((INodeData_TAR_ITEM)N.NodeData).TAR_IsDirectory) B.Length--;
                        ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName = B.ToString();

                        if (((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName == "././@LongLink") // Dlhy nazov?
                        {
                            Expand_ReadBuffer(); // Citam buffer

                            B.Length = 0;
                            for (i = 0; i < 512; i++) // Citam nazov
                            {
                                if (FExpand_Buffer[i] == 0) break;
                            }
                            B.Append(E.GetString(FExpand_Buffer, 0, i));
                            ((INodeData_TAR_ITEM)N.NodeData).TAR_IsDirectory = B[B.Length - 1] == '/';
                            if (((INodeData_TAR_ITEM)N.NodeData).TAR_IsDirectory) B.Length--;
                            ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName = B.ToString();

                            Expand_ReadBuffer(); // Citam buffer
                        }

                        if (!IsValidTARHeader(FExpand_Buffer))
                        {
                            LastError = lang.NODE_LIST_TAR_ARCHIVE_TEXT_12;
                            return -1;
                        }

                        ((INodeData_TAR_ITEM)N.NodeData).TAR_OriginalSize = Octal2Long(FExpand_Buffer, 124, 12);
                        ((INodeData_TAR_ITEM)N.NodeData).TAR_ModifyDate = (uint)Octal2Int(FExpand_Buffer, 136, 12); // Datum modifikacie

                        B.Length = 0;
                        for (i = 0; i < 32; i++) // Citam uzivatela
                        {
                            if (FExpand_Buffer[i + 265] == 0) break;
                        }
                        if (i > 0) B.Append(E.GetString(FExpand_Buffer, 265, i));
                        ((INodeData_TAR_ITEM)N.NodeData).TAR_UserID = B.ToString();

                        B.Length = 0;
                        for (i = 0; i < 32; i++) // Citam skupinu
                        {
                            if (FExpand_Buffer[i + 297] == 0) break;
                        }
                        if (i > 0) B.Append(E.GetString(FExpand_Buffer, 297, i));

                        ((INodeData_TAR_ITEM)N.NodeData).TAR_GroupID = B.ToString();
                        ((INodeData_TAR_ITEM)N.NodeData).TAR_FileMode = (uint)Octal2Int(FExpand_Buffer, 100, 8);
                        ((INodeData_TAR_ITEM)N.NodeData).TAR_DataPosition = FExpand_CurrentPosition;

                        WriteNodeToCache(N); // Zapisem do cache

                        FExpand_TotalCount++;
                        if (!IsItemInCurrentLevel(P1, ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName))
                        {
                            Expand_SkipBytes(((((INodeData_TAR_ITEM)N.NodeData).TAR_OriginalSize & 0x1ff) != 0) ? ((((INodeData_TAR_ITEM)N.NodeData).TAR_OriginalSize / 512) + 1) * 512 : (((INodeData_TAR_ITEM)N.NodeData).TAR_OriginalSize / 512) * 512);
                            if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_TAR_ARCHIVE_TEXT_14, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                            continue;
                        }
                        int I = ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName.LastIndexOf('/');
                        if (I != -1) ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName = ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName.Substring(I + 1); // Ziskam nazov bez cesty

                        if (Result == null)
                        {
                            if (((INodeData_TAR_ITEM)N.NodeData).TAR_IsDirectory) FExpand_Dirs.Add(N); else FExpand_Files.Add(N);
                            if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_TAR_ARCHIVE_TEXT_14, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                        }

                        Expand_SkipBytes(((((INodeData_TAR_ITEM)N.NodeData).TAR_OriginalSize & 0x1ff) != 0) ? ((((INodeData_TAR_ITEM)N.NodeData).TAR_OriginalSize / 512) + 1) * 512 : (((INodeData_TAR_ITEM)N.NodeData).TAR_OriginalSize / 512) * 512);
                    }

                    return 1;
                }
            }
            catch
            {
                return -1;
            }
        }

        /// <summary>Vytvorenie textov pre zobrazenie</summary>
        /// <param name="pNode">objekt node</param>
        public override void CreateDisplayStrings(INode pNode)
        {
            if (pNode.DisplayStrings != null) return; // Uz su vytvorenie?

            pNode.DisplayStrings = new string[ColsCount]; // Alokujem retazec
            switch (pNode.ID) // Podla typu node
            {
                case INode.NODE_ID_BACK_ITEM:
                    {
                        pNode.DisplayStrings[0] = ICore.BoundString("[", "..", "]", IApp.Settings.FileExplorer_DirsInBraces);
                        pNode.DisplayStrings[2] = FRelativePath == "" ? lang.NODE_LIST_TAR_ARCHIVE_TEXT_8 : lang.NODE_LIST_TAR_ARCHIVE_TEXT_9;
                        pNode.DefaultImageIndex = -1;
                    } break;
                case INode.NODE_ID_TAR_ITEM:
                    {
                        if (((INodeData_TAR_ITEM)pNode.NodeData).TAR_IsDirectory)
                        {
                            pNode.DisplayStrings[0] = pNode.Name; // Len nazov
                            if (pNode.ValidSize) pNode.DisplayStrings[2] = ICore.Size2String((ulong)pNode.Size, IApp.Settings.FileExplorer_DisplaySizeMode);
                            else pNode.DisplayStrings[2] = lang.NODE_LIST_TAR_ARCHIVE_TEXT_10;
                            pNode.DefaultImageIndex = 0;
                        }
                        else
                        {
                            pNode.DisplayStrings[0] = pNode.NameOnly; // Len nazov
                            if (pNode.DisplayStrings[0] == "") pNode.DisplayStrings[0] = pNode.Name; else pNode.DisplayStrings[1] = pNode.Ext; // Pripona
                            pNode.DisplayStrings[2] = ICore.Size2String((ulong)((INodeData_TAR_ITEM)pNode.NodeData).TAR_OriginalSize, IApp.Settings.FileExplorer_DisplaySizeMode); // Velkost
                            pNode.DefaultImageIndex = 1;
                        }
                        pNode.DisplayStrings[3] = ICore.DateTime2Str(pNode.DLastModify);
                        pNode.DisplayStrings[4] = ICore.UnixModeToString(((INodeData_TAR_ITEM)pNode.NodeData).TAR_FileMode);
                        pNode.DisplayStrings[5] = ((INodeData_TAR_ITEM)pNode.NodeData).TAR_UserID;
                        pNode.DisplayStrings[6] = ((INodeData_TAR_ITEM)pNode.NodeData).TAR_GroupID;
                    } break;
            }
        }
        /// <summary>Triedenie obsahu zoznamu</summary>
        /// <param name="pColumn">stlpec</param>
        /// <param name="pAsc">smer</param>
        public override void Sort(int pColumn, bool pAsc)
        {
            int S = IsBackNode(0) ? 1 : 0; // Urcim zaciatok
            if (DirsCount > 1)
            {
                FItems.Sort(S, DirsCount, new INodeComparer(0, pAsc));
            }
            if (FilesCount > 1)
            {
                FItems.Sort(S + DirsCount, FilesCount, new INodeComparer(pColumn, pAsc));
            }
        }
        /// <summary>Vytvorenie klonu zoznamu</summary>
        /// <returns>objekt zoznamu</returns>
        public override INodeList CloneList()
        {
            return new INodeList_TAR(FBaseArchiveFileName, FRelativePath);
        }

        /// <summary>Nastavenie zoznamu do modu zdroja extrahovania</summary>
        /// <param name="pItemsToExtract">polozky na extrahovanie</param>
        /// <param name="pProgressForm">progress formular</param>
        public override void BeginSourceExtractMode(System.Collections.Generic.List<string> pItemsToExtract = null, IFileExplorer_ProgressForm_ExtractArchive pProgressForm = null)
        {
            FExtract_ArchiveFile = null;
            FExtract_CurrentItem = new INode();
            CopyMode_NativeDataBuffer = new byte[MAX_COPY_BUFFER_SIZE];
            FExtract_SkipBytesCount = 0;

            if (pItemsToExtract == null) FExtract_ListOfItems = null;
            else
            {
                FExtract_ListOfItemsRoot = null;
                FExtract_ListOfItems = new System.Collections.Generic.List<string>();
                foreach (string S in pItemsToExtract) // Vytvorim relativne cesty
                {
                    int I = S.LastIndexOf(":\\");
                    if (I != -1)
                    {
                        string S1 = S.Substring(I + 2);
                        FExtract_ListOfItems.Add(S1);
                        if (FExtract_ListOfItemsRoot == null) FExtract_ListOfItemsRoot = S1;
                        else
                        {
                            if (FExtract_ListOfItemsRoot.Length > 0)
                            {
                                int i;
                                for (i = 0; i < FExtract_ListOfItemsRoot.Length; i++)
                                {
                                    if (i >= S1.Length) break;
                                    if (char.ToLower(FExtract_ListOfItemsRoot[i]) != char.ToLower(S1[i])) break;
                                }
                                if (i != FExtract_ListOfItemsRoot.Length) FExtract_ListOfItemsRoot = i == 0 ? "" : FExtract_ListOfItemsRoot.Substring(0, i);
                            }
                        }
                    }
                }
                if (string.IsNullOrEmpty(FExtract_ListOfItemsRoot)) FExtract_ListOfItemsRoot = "";
                else
                {
                    int I = FExtract_ListOfItemsRoot.LastIndexOf('\\');
                    FExtract_ListOfItemsRoot = I == -1 ? "" : FExtract_ListOfItemsRoot.Substring(0, I + 1);
                }

                FExtractMode_ItemsToExpandList = new System.Collections.Generic.Dictionary<string,int>(); // Vytvorim cache poloziek
                foreach (string FN in pItemsToExtract) FExtractMode_ItemsToExpandList.Add(FN.Substring(FBaseArchiveFileName.Length + 2).ToLower(), 0);
            }
        }
        /// <summary>Uzatvorenie modu extrahovania</summary>
        public override void CloseExtractMode()
        {
            FExtract_ArchiveFile = (System.IO.BinaryReader)ICore.DisposeObject(FExpand_ArchiveFile);
            FExtract_CurrentItem = (INode)ICore.DisposeObject(FExtract_CurrentItem);
            CopyMode_NativeDataBuffer = null;
        }
        /// <summary>Ziskanie dalsieho zaznamu na extrahovanie</summary>
        /// <param name="Result">vysledne data</param>
        /// <returns>0 - koniec, 1 - platny zaznam, alebo kod chyby</returns>
        public override int ExtractMode_GetNextSourceItem(INode Result)
        {
            try
            {
                if (FExtract_ArchiveFile == null) FExtract_ArchiveFile = TestArchive_OpenStream(FBaseArchiveFileName);
                while (true)
                {
                    SkipBytesInStream(FExtract_ArchiveFile, FExtract_SkipBytesCount);
                    //FExtract_ArchiveFile.BaseStream.Position += FExtract_SkipBytesCount;

                    FExtract_ArchiveFile.Read(CopyMode_NativeDataBuffer, 0, 512); // Citam header
                    if (CopyMode_NativeDataBuffer[0] == 0) return 0; // Posledny zaznam?

                    FExtract_CurrentItem.ID = INode.NODE_ID_TAR_ITEM;
                    FExtract_CurrentItem.NodeData = new INodeData_TAR_ITEM();

                    System.Text.StringBuilder B = new System.Text.StringBuilder();

                    int i;
                    for (i = 0; i < 100; i++) // Citam nazov
                    {
                        if (CopyMode_NativeDataBuffer[i] == 0) break;
                    }
                    B.Append(System.Text.Encoding.Default.GetString(CopyMode_NativeDataBuffer, 0, i));
                    ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_IsDirectory = B[B.Length - 1] == '/';
                    if (((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_IsDirectory) B.Length--;
                    ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_ItemName = B.ToString();

                    if (((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_ItemName == "././@LongLink") // Dlhy nazov?
                    {
                        FExtract_ArchiveFile.Read(CopyMode_NativeDataBuffer, 0, 512); // Citam buffer

                        B.Length = 0;
                        for (i = 0; i < 512; i++) // Citam nazov
                        {
                            if (CopyMode_NativeDataBuffer[i] == 0) break;
                        }
                        B.Append(System.Text.Encoding.Default.GetString(CopyMode_NativeDataBuffer, 0, i));
                        ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_IsDirectory = B[B.Length - 1] == '/';
                        if (((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_IsDirectory) B.Length--;
                        ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_ItemName = B.ToString();

                        FExtract_ArchiveFile.Read(CopyMode_NativeDataBuffer, 0, 512); // Citam buffer
                    }

                    if (!IsValidTARHeader(CopyMode_NativeDataBuffer))
                    {
                        LastError = lang.NODE_LIST_TAR_ARCHIVE_TEXT_12;
                        return -1;
                    }

                    ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_OriginalSize = Octal2Long(CopyMode_NativeDataBuffer, 124, 12);
                    ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_ModifyDate = (uint)Octal2Int(CopyMode_NativeDataBuffer, 136, 12); // Datum modifikacie

                    B.Length = 0;
                    for (i = 265; i < 32; i++) // Citam uzivatela
                    {
                        if (CopyMode_NativeDataBuffer[i] == 0) break;
                        B.Append((char)CopyMode_NativeDataBuffer[i]);
                    }
                    ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_UserID = B.ToString();

                    B.Length = 0;
                    for (i = 297; i < 32; i++) // Citam skupinu
                    {
                        if (CopyMode_NativeDataBuffer[i] == 0) break;
                        B.Append((char)CopyMode_NativeDataBuffer[i]);
                    }
                    ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_GroupID = B.ToString();
                    ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_FileMode = (uint)Octal2Int(CopyMode_NativeDataBuffer, 100, 8);

                    Result.RelativeName = ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_ItemName.Replace('/', '\\');
                    FExtract_CurrentItem.RelativeName = Result.RelativeName;

                    Result.ID = FExtract_CurrentItem.ID;
                    Result.NodeData = new INodeData_TAR_ITEM();
                    ((INodeData_TAR_ITEM)Result.NodeData).TAR_FileMode = ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_FileMode;
                    ((INodeData_TAR_ITEM)Result.NodeData).TAR_GroupID = ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_GroupID;
                    ((INodeData_TAR_ITEM)Result.NodeData).TAR_IsDirectory = ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_IsDirectory;
                    ((INodeData_TAR_ITEM)Result.NodeData).TAR_ModifyDate = ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_ModifyDate;
                    ((INodeData_TAR_ITEM)Result.NodeData).TAR_OriginalSize = ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_OriginalSize;
                    ((INodeData_TAR_ITEM)Result.NodeData).TAR_UserID = ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_UserID;

                    int I = ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_ItemName.LastIndexOf('/');
                    if (I != -1) ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_ItemName = ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_ItemName.Substring(I + 1); // Ziskam nazov bez cesty
                    ((INodeData_TAR_ITEM)Result.NodeData).TAR_ItemName = ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_ItemName;

                    long S = ((((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_OriginalSize & 0x1ff) != 0) ? ((((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_OriginalSize / 512) + 1) * 512 : (((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_OriginalSize / 512) * 512;
                    FExtract_SkipBytesCount = (int)(S - ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_OriginalSize);
                    FExtract_CurrentItemReaded = 0;

                    return 1;
                }
            }
            catch
            {
                return -1;
            }
        }
        /// <summary>Ziskanie nazvu aktualneho spracovavaneho zaznamu</summary>
        /// <returns>nazov</returns>
        public override string ExtractMode_CurrentName()
        {
            return FExtract_CurrentItem.Name;
        }
        /// <summary>Otvorenie aktualneho suboru na citanie</summary>
        /// <returns>0 alebo kod chyby</returns>
        public override int ExtractMode_OpenCurrentFileForRead()
        {
            try
            {
                FExtract_CurrentItemReaded = 0;
                return 0;
            }
            catch
            {
                return IFileSystem.FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Uzatvorenie aktualneho suboru otvoreneho na citanie</summary>
        public override void ExtractMode_CloseReadFile()
        {
        }
        /// <summary>Preskocenie aktualneho zaznamu z extrahovania</summary>
        public override void ExtractMode_SkipCurrentItem()
        {
            SkipBytesInStream(FExtract_ArchiveFile, ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_OriginalSize - FExtract_CurrentItemReaded);
            //FExtract_ArchiveFile.BaseStream.Position += FExtract_CurrentItem.TAR_OriginalSize - FExtract_CurrentItemReaded;
        }
        /// <summary>Nacitanie obsahu</summary>
        /// <param name="pMaxLength">max. dlzka</param>
        /// <param name="pResultBuffer">vysledny buffer alebo null pre interny</param>
        /// <returns>pocet nacitanych bajtov alebo kod chyby</returns>
        public override int ExtractMode_ReadFile(int pMaxLength, byte[] pResultBuffer)
        {
            try
            {
                long C = ((INodeData_TAR_ITEM)FExtract_CurrentItem.NodeData).TAR_OriginalSize - FExtract_CurrentItemReaded;
                if (C > pMaxLength) C = pMaxLength;
                if (C == 0) return 0;

                int R = FExtract_ArchiveFile.Read(pResultBuffer, 0, (int)C);
                FExtract_CurrentItemReaded += R;
                return R;
            }
            catch
            {
                return IFileSystem.FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Test potreby extrahovania aktualneho zaznamu</summary>
        /// <param name="DestRelativePath">vysledna relativna cesta</param>
        /// <returns>true / false</returns>
        public override bool ExtractMode_CurrentNeedExpand(ref string DestRelativePath)
        {
            return NeedToBeExtracted(FExtract_ListOfItemsRoot, FExtract_CurrentItem.RelativeName, FExtract_ListOfItems, ref DestRelativePath); // Ma sa extrahovat?
        }

        /// <summary>Ziskanie statistickych informacii pre proces extrahovania</summary>
        /// <param name="ResultStatData">vysledna stat. data</param>
        /// <param name="pItems">zoznam poloziek pre spocitanie</param>
        /// <param name="pBreakState">premenna pre oznamenie o preruseni spracovania</param>
        /// <returns>true / false</returns>
        public override bool Run_GetExtractStatsInfo(IComputeOccupiedSpaceData ResultStatData, System.Collections.Generic.List<string> pItems = null, IThrSafeVariable pBreakState = null)
        {
            try // Test hlavicky a nacitanie dat
            {
                string FN = "";
                BeginSourceExtractMode(pItems);

                using (INode N = new INode())
                {
                    while (true)
                    {
                        int R = ExtractMode_GetNextSourceItem(N); // Ziskam polozku
                        if (R < 0)
                        {
                            CloseExtractMode();
                            return false;
                        }
                        if (R != 1) break;

                        if (ExtractMode_CurrentNeedExpand(ref FN))
                        {
                            if (((INodeData_TAR_ITEM)N.NodeData).TAR_IsDirectory) ResultStatData.AddDir(); // Zaradim do statistiky
                            else ResultStatData.AddFile(((INodeData_TAR_ITEM)N.NodeData).TAR_OriginalSize);
                        }

                        ExtractMode_SkipCurrentItem(); // Preskocim data
                        if (pBreakState.BoolValue)
                        {
                            CloseExtractMode();
                            return false;
                        }
                    }
                }

                CloseExtractMode();
                return true;
            }
            catch
            {
                return false; // Chyba
            }
        }
        /// <summary>Spustenie procesu kontroly archivu GZIP</summary>
        /// <param name="pErrorMsg">chybova sprava</param>
        /// <param name="pProgressForm">progress formular</param>
        /// <returns>true / false</returns>
        public override bool TestArchive(out string pErrorMsg, IFileExplorer_ProgressForm_TestArchive pProgressForm = null)
        {
            pErrorMsg = ""; // Inicializacia
            if (pProgressForm != null) pProgressForm.StartArchive(FBaseArchiveFileName, ArchiveTypeString);

            try
            {
                byte[] Buffer = new byte[512]; System.Text.StringBuilder B = new System.Text.StringBuilder();
                using (System.IO.BinaryReader R = TestArchive_OpenStream(FBaseArchiveFileName))
                {
                    while (true)
                    {
                        R.Read(Buffer, 0, 512); // Citam header
                        if (Buffer[0] == 0) break; // Posledny zaznam?

                        if (!IsValidTARHeader(Buffer))
                        {
                            pErrorMsg = string.Format(lang.NODE_LIST_TAR_ARCHIVE_TEXT_13, ArchiveTypeString);
                            return false; // Chyba
                        }

                        B.Length = 0;
                        for (int i = 0; i < 100; i++) // Citam nazov
                        {
                            if (Buffer[i] == 0) break;
                            B.Append((char)Buffer[i]);
                        }

                        if (B.ToString() == "././@LongLink") // Dlhy nazov?
                        {
                            R.Read(Buffer, 0, 512); // Citam header
                            B.Length = 0;
                            for (int i = 0; i < 512; i++) // Citam nazov
                            {
                                if (Buffer[i] == 0) break;
                                B.Append((char)Buffer[i]);
                            }
                            R.Read(Buffer, 0, 512); // Citam header
                            if (!IsValidTARHeader(Buffer)) // Test integrity
                            {
                                pErrorMsg = string.Format(lang.NODE_LIST_TAR_ARCHIVE_TEXT_13, ArchiveTypeString);
                                return false; // Chyba
                            }
                        }

                        bool IsDir = B[B.Length - 1] == '/'; // Urcim priznak priecinku
                        if (IsDir) B.Length--; // Urcim nazov bez cesty
                        string FN = B.ToString();
                        int I = FN.LastIndexOf('/');
                        if (I != -1) FN = FN.Substring(I + 1);

                        if (pProgressForm != null) // Zobrazuje sa progress?
                        {
                            if (pProgressForm.WaitForTerminate.BoolValue) return false;
                            if (IsDir) pProgressForm.AddDir(); else { pProgressForm.StartFile(FN); pProgressForm.FinishFile(); }
                        }

                        long Size = Octal2Long(Buffer, 124, 12);
                        Size = ((Size & 0x1ff) != 0) ? ((Size / 512) + 1) * 512 : (Size / 512) * 512;
                        SkipBytesInStream(R, Size); // Posuniem poziciu
                    }
                }
                return true; // Test prebehol OK
            }
            catch
            {
                pErrorMsg = string.Format(lang.NODE_LIST_TAR_ARCHIVE_TEXT_13, ArchiveTypeString);
                return false; // Chyba
            }
        }
        /// <summary>Spustenie hladania nad zoznamom</summary>
        /// <param name="pData">udaje pre hladanie</param>
        /// <param name="pProgressForm">progress formular</param>
        /// <returns>true / false</returns>
        public override bool Run_Search(ISearchDataStruct pData, int pDepth, IFileExplorer_ProgressForm_Search pProgressForm = null)
        {
            try
            {
                byte[] Buffer = new byte[512]; System.Text.StringBuilder B = new System.Text.StringBuilder();
                using (INode N = new INode()) {
                    using (System.IO.BinaryReader R = TestArchive_OpenStream(FBaseArchiveFileName))
                    {
                        while (true)
                        {
                            if ((pProgressForm != null) && (pProgressForm.WaitForTerminate.BoolValue)) return false;

                            R.Read(Buffer, 0, 512); // Citam header
                            if (Buffer[0] == 0) return true; // Posledny zaznam?

                            if (!IsValidTARHeader(Buffer))
                            {
                                return true; // Chyba
                            }

                            N.ID = INode.NODE_ID_TAR_ITEM;
                            N.NodeData = new INodeData_TAR_ITEM();

                            B.Length = 0;
                            for (int i = 0; i < 100; i++) // Citam nazov
                            {
                                if (Buffer[i] == 0) break;
                                B.Append((char)Buffer[i]);
                            }
                            ((INodeData_TAR_ITEM)N.NodeData).TAR_IsDirectory = B[B.Length - 1] == '/';
                            if (((INodeData_TAR_ITEM)N.NodeData).TAR_IsDirectory) B.Length--;
                            ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName = B.ToString();

                            if (((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName == "././@LongLink") // Dlhy nazov?
                            {
                                R.Read(Buffer, 0, 512); // Citam header

                                B.Length = 0;
                                for (int i = 0; i < 512; i++) // Citam nazov
                                {
                                    if (Buffer[i] == 0) break;
                                    B.Append((char)Buffer[i]);
                                }
                                ((INodeData_TAR_ITEM)N.NodeData).TAR_IsDirectory = B[B.Length - 1] == '/';
                                if (((INodeData_TAR_ITEM)N.NodeData).TAR_IsDirectory) B.Length--;
                                ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName = B.ToString();

                                R.Read(Buffer, 0, 512); // Citam header
                            }

                            if (!IsValidTARHeader(Buffer)) return true;

                            ((INodeData_TAR_ITEM)N.NodeData).TAR_OriginalSize = Octal2Long(Buffer, 124, 12);
                            ((INodeData_TAR_ITEM)N.NodeData).TAR_ModifyDate = (uint)Octal2Int(Buffer, 136, 12); // Datum modifikacie

                            B.Length = 0;
                            for (int i = 265; i < 32; i++) // Citam uzivatela
                            {
                                if (Buffer[i] == 0) break;
                                B.Append((char)Buffer[i]);
                            }
                            ((INodeData_TAR_ITEM)N.NodeData).TAR_UserID = B.ToString();

                            string OldName = ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName.Replace('/', '\\');
                            int I = ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName.LastIndexOf('/');
                            if (I != -1) ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName = ((INodeData_TAR_ITEM)N.NodeData).TAR_ItemName.Substring(I + 1); // Ziskam nazov bez cesty

                            long Size = ((((INodeData_TAR_ITEM)N.NodeData).TAR_OriginalSize & 0x1ff) != 0) ? ((((INodeData_TAR_ITEM)N.NodeData).TAR_OriginalSize / 512) + 1) * 512 : (((INodeData_TAR_ITEM)N.NodeData).TAR_OriginalSize / 512) * 512;
                            string FullPath = FBaseArchiveFileName + ":\\" + OldName;

                            if (N.IsDirectory) // Priecinok?
                            {
                                if ((!pData.SearchInContent) || (pData.SearchContentValue == "")) // V pripade hladania v obsahu sa priecinky do vysledku nezaradia
                                {
                                    if (pData.SearchPartialName) // Hladat cast mena?
                                    {
                                        if ((pData.SearchNameValue == "") || (INodeFilter.WildcardMatch(N.Name.ToLower(), pData.SearchNameValue.ToLower()))) // Porovnam ako wildcards
                                        {
                                            if (pData.SearchExtFilter.TestNode(N)) // Test filtra
                                            {
                                                if (pProgressForm != null) pProgressForm.AddResult(FullPath, 0, true, N.Attributes, N.DLastModify, true, N.ID); // Zaradim ako vysledok hladania
                                            }
                                        }
                                    }
                                    else
                                    {
                                        if ((pData.SearchNameValue == "") || (string.Compare(N.Name, pData.SearchNameValue, true) == 0)) // Porovnam presne s menom
                                        {
                                            if (pData.SearchExtFilter.TestNode(N)) // Testujem filter
                                            {
                                                if (pProgressForm != null) pProgressForm.AddResult(FullPath, 0, true, N.Attributes, N.DLastModify, true, N.ID); // Zaradim ako vysledok hladania
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                bool IsIn = false; // Priznak platneho testu nazvu
                                if (pData.SearchPartialName) // Cast mena
                                {
                                    if ((pData.SearchNameValue == "") || (INodeFilter.WildcardMatch(N.Name.ToLower(), pData.SearchNameValue.ToLower()))) // Wildcars porovnanie
                                    {
                                        if (pData.SearchExtFilter.TestNode(N)) // Test filtra
                                        {
                                            if (!pData.SearchInContent) // Nehladat v obsahu
                                            {
                                                if (pProgressForm != null) pProgressForm.AddResult(FullPath, N.Size, false, N.Attributes, N.DLastModify, true, N.ID); // Zaradim ako vysledok hladania
                                            }
                                            IsIn = true; // Oznacim ze presiel
                                        }
                                    }
                                }
                                else
                                {
                                    if ((pData.SearchNameValue == "") || (string.Compare(N.Name, pData.SearchNameValue, true) == 0)) // Test plneho mena
                                    {
                                        if (pData.SearchExtFilter.TestNode(N)) // Test filtra
                                        {
                                            if (!pData.SearchInContent) // Nehladat v obsahu?
                                            {
                                                if (pProgressForm != null) pProgressForm.AddResult(FullPath, N.Size, false, N.Attributes, N.DLastModify, true, N.ID); // Zaradim ako vysledok hladania
                                            }
                                            IsIn = true; // Oznacim ze presiel
                                        }
                                    }
                                }

                                if ((IsIn) && (pData.SearchInContent)) // Prehladavat obsah?
                                {
                                    if (string.IsNullOrEmpty(pData.SearchContentValue)) // Hladana hodnota je prazdna? - obsah sa prehlasi za true
                                    {
                                        if (!pData.SearchInContent_NotInContent) // Zaradovat true?
                                        {
                                            if (pProgressForm != null) pProgressForm.AddResult(FullPath, N.Size, false, N.Attributes, N.DLastModify, true, N.ID); // Zaradim ako vysledok hladania
                                        }
                                    }
                                    else
                                    {
                                        // Idem prehladavat obsah
                                        using (ISearchInContentStream CntStream = new ISearchInContentStream()) // Vytvorim hladaci stream
                                        {
                                            try
                                            {
                                                long ToRead = ((INodeData_TAR_ITEM)N.NodeData).TAR_OriginalSize; long Readed = 0;
                                                CntStream.Init(pData.SearchContentValue, pData.SearchInContent_CaseSensitive, pData.SearchInContent_EncodingType); // Inicializujem stream
                                                CntStream.GetData += (pBuffer, pStart, pMaxLength) => // Event na dodanie dat streamu
                                                {
                                                    try
                                                    {
                                                        if (ToRead == 0)
                                                        {
                                                            return 0; // Koniec?
                                                        }

                                                        long C = pMaxLength;
                                                        if (C > ToRead) C = ToRead; // Urcim, kolko mozem citat
                                                        int C1 = R.Read(pBuffer, pStart, (int)C); // Citam
                                                        ToRead -= C1; Readed += C1;
                                                        return C1; // Vratim pocet nacitanych
                                                    }
                                                    catch
                                                    {
                                                        return 0;
                                                    }
                                                };
                                                int Res = CntStream.Find(pProgressForm); // Hladam
                                                if (Res == ISearchInContentStream.FIND_YES) // Nasiel som?
                                                {
                                                    if (!pData.SearchInContent_NotInContent) // Zaradoivat true vysledky?
                                                    {
                                                        if (pProgressForm != null) pProgressForm.AddResult(FullPath, N.Size, false, N.Attributes, N.DLastModify, true, N.ID); // Zaradim ako vysledok hladania
                                                    }
                                                }
                                                else // Nenasiel som
                                                {
                                                    if (pData.SearchInContent_NotInContent) // Zaradovat false vysledky?
                                                    {
                                                        if (pProgressForm != null) pProgressForm.AddResult(FullPath, N.Size, false, N.Attributes, N.DLastModify, true, N.ID); // Zaradim ako vysledok hladania
                                                    }
                                                }
                                                Size -= Readed;
                                            }
                                            catch // Pri chybe jednoducho nic nezaradim
                                            {
                                            }
                                        }
                                    }
                                }
                            }

                            SkipBytesInStream(R, Size); // Posuniem poziciu
                        }
                    }
                }
            }
            catch
            {
                return true; // Chyba
            }
        }

        /// <summary>Prevod osmickoveho cisla na velkost</summary>
        /// <param name="pData">data</param>
        /// <param name="pStart">zaciatok citania</param>
        /// <param name="pMaxLength">max. dlzka</param>
        /// <returns>vysledok</returns>
        public static int Octal2Int(byte[] pData, int pStart, int pMaxLength)
        {
            int Result = 0;
            bool FindNumber = false;

            if ((pData[pStart] & 0x80) != 0)
            {
                for (int i = pStart + 1; i < pStart + pMaxLength; i++)
                {
                    Result <<= 8; Result |= pData[i];
                }
            }
            else
            {
                for (int i = pStart; i < pStart + pMaxLength; i++)
                {
                    if (pData[i] <= ' ')
                    {
                        if (FindNumber) break;
                        continue;
                    }
                    Result <<= 3; Result |= (byte)(pData[i] - (byte)'0');
                    FindNumber = true;
                }
            }

            return Result;
        }
        /// <summary>Prevod osmickoveho cisla na velkost</summary>
        /// <param name="pData">data</param>
        /// <param name="pStart">zaciatok citania</param>
        /// <param name="pMaxLength">max. dlzka</param>
        /// <returns>vysledok</returns>
        public static long Octal2Long(byte[] pData, int pStart, int pMaxLength)
        {
            long Result = 0;
            bool FindNumber = false;

            if ((pData[pStart] & 0x80) != 0)
            {
                Result = System.Net.IPAddress.NetworkToHostOrder(BitConverter.ToInt64(pData, 128));
            }
            else
            {
                for (int i = pStart; i < pStart + pMaxLength; i++)
                {
                    if (pData[i] <= ' ')
                    {
                        if (FindNumber) break;
                        continue;
                    }
                    Result <<= 3; Result |= (byte)(pData[i] - (byte)'0');
                    FindNumber = true;
                }
            }

            return Result;
        }
        /// <summary>Test ci nazov polozky patri do zadanej urovne relativnej cesty</summary>
        /// <param name="pRelativePath">relativna cesta</param>
        /// <param name="pItemName">nazov polozky</param>
        /// <returns>true / false</returns>
        public static bool IsItemInCurrentLevel(string pRelativePath, string pItemName)
        {
            if (pRelativePath == "/") return pItemName.IndexOf('/') == -1; // Som v roote?
            if (string.Compare(pItemName, 0, pRelativePath, 0, pRelativePath.Length, true) != 0) return false; // Som v dobrom podpriecinku?
            return pItemName.IndexOf('/', pRelativePath.Length + 1) == -1;
        }
        /// <summary>Vypocet CRC hlavicky</summary>
        /// <param name="pData">data</param>
        /// <param name="pLength">dlzka</param>
        /// <returns>CRC</returns>
        public static uint CalculateCRC(byte[] pData, int pLength = 500)
        {
            uint Result = 0;
            for (int i = 0; i < 148; i++) Result += pData[i];
            Result += 32 * 8;
            for (int i = 156; i < pLength; i++) Result += pData[i];
            return Result;
        }
        /// <summary>Test neporusenosti hlavicky</summary>
        /// <param name="pData">data</param>
        /// <returns>true / false</returns>
        public static bool IsValidTARHeader(byte[] pData)
        {
            return CalculateCRC(pData, 512) == (uint)Octal2Int(pData, 148, 8);
        }
        /// <summary>Test ci zadany objekt je potrebne extrahovat</summary>
        /// <param name="pSourceRoot">spolocny root zoznamu</param>
        /// <param name="pRelativeName">nazov objektu</param>
        /// <param name="pList">zoznam objektov pre extrahovanie</param>
        /// <param name="DestRelativePath">vysledna relativna cesta</param>
        /// <returns>true / false</returns>
        public static bool NeedToBeExtracted(string pSourceRoot, string pRelativeName, System.Collections.Generic.List<string> pList, ref string DestRelativePath)
        {
            if (pList == null) return true; // Vsetky?

            foreach (string S in pList) // Prechadzam zoznam
            {
                if (pRelativeName.Length < S.Length) continue; // Test dlzky
                if (string.Compare(pRelativeName, S, false) == 0)
                {
                    if (DestRelativePath == "") return true;
                    DestRelativePath = DestRelativePath.Substring(pSourceRoot.Length);
                    return true;
                }
                string S1 = S + "\\";
                if (string.Compare(pRelativeName, 0, S1, 0, S1.Length, false) == 0)
                {
                    if (DestRelativePath == "") return true;
                    DestRelativePath = DestRelativePath.Substring(pSourceRoot.Length);
                    return true;
                }
            }
            return false;
        }

        /// <summary>Spustenie procesu vytvorenia archivu</summary>
        /// <param name="pData">data</param>
        /// <param name="pItems">zoznam poloziek na archivaciu</param>
        /// <param name="pProgressForm">progress formular</param>
        /// <returns>true / false</returns>
        public static bool Run_CreateArchive_TAR(ICompressionDataStr pData, System.Collections.Generic.List<string> pItems, IFileExplorer_ProgressForm_CompressItems pProgressForm = null)
        {
            IConfirmationFlags Flags = new IConfirmationFlags();
            int R;

            INodeList SourceList = INodeList.CreateNodeList(IFileSystem.ExtractPath(pItems[0]));
            if (SourceList == null) return false; // Chybna zdrojova cesta?
            using (SourceList)
            {
                INodeList DestList = INodeList.CreateNodeList(IFileSystem.ExtractPath(pData.DestinationArchiveName));
                if (DestList == null) return false; // Chybna cielova cesta?
                using (DestList)
                {
                    SourceList.BeginSourceCopyMode();
                    DestList.BeginDestinationCopyMode();

                    System.IO.Stream DestStream_File = null;
                    System.IO.Stream DestStream;

                    while (true)
                    {
                        DestStream_File = DestList.CopyMode_CreateStreamForWrite(IFileSystem.ExtractName(pData.DestinationArchiveName), out R, Flags.ForceOverwriteDestinationFile, Flags.ForceOverwriteReadOnlyDestinationFile, Flags.ForceOverwriteSystemDestinationFile, Flags.ForceOverwriteSystemDestinationFile); // Vytvorim cielovy subor

                        if (R == 0) break; // OK..

                        switch (R)
                        {
                            case IFileSystem.FS_ERROR_FILE_EXISTS:
                                {
                                    if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_8_1, pData.DestinationArchiveName), lang.FILE_EXPLORER_TEXT_39_8_2, lang.FILE_EXPLORER_TEXT_39_8_3, ref Flags.OverwriteDestinationFile)) return false;
                                } break;
                            case IFileSystem.FS_ERROR_READ_ONLY_ATTRIBUTE:
                                {
                                    if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_9_1, pData.DestinationArchiveName), lang.FILE_EXPLORER_TEXT_39_9_2, lang.FILE_EXPLORER_TEXT_39_9_3, ref Flags.OverwriteReadOnlyDestinationFile)) return false;
                                } break;
                            case IFileSystem.FS_ERROR_SYSTEM_ATTRIBUTE:
                            case IFileSystem.FS_ERROR_HIDDEN_ATTRIBUTE:
                                {
                                    if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_10_1, pData.DestinationArchiveName), lang.FILE_EXPLORER_TEXT_39_10_2, lang.FILE_EXPLORER_TEXT_39_10_3, ref Flags.OverwriteSystemDestinationFile)) return false;
                                } break;
                            default:
                                {
                                    if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_11_1, pData.DestinationArchiveName), lang.FILE_EXPLORER_TEXT_39_11_2, lang.FILE_EXPLORER_TEXT_39_11_3, ref Flags.CreateDestinationFileError)) return false;
                                } break;
                        }
                    }

                    DestStream = (pData.CompressionType == ICompressionDataStr.COMPRESSION_TYPE_TAR) ? DestStream_File : new System.IO.Compression.GZipStream(DestStream_File, System.IO.Compression.CompressionMode.Compress, true);
                    ITARArchiveCreator TarArchive = new ITARArchiveCreator(DestStream);

                    using (TarArchive)
                    {
                        bool IsFolder;
                        foreach (string FN in pItems)
                        {
                            if ((pProgressForm != null) && (pProgressForm.WaitForTerminate.BoolValue)) return false;

                            string RelFN = SourceList.CopyMode_MakeRelative(FN, out IsFolder);
                            if (RelFN == "") continue;

                            if (IsFolder)
                            {
                                if (Run_CreateArchive_TAR_AddDir(Flags, pData, TarArchive, RelFN, SourceList, null, pProgressForm) == -1)
                                {
                                    DestStream.Close(); DestStream.Dispose();
                                    DestList.CopyMode_CloseStreamForWrite(DestStream_File, true);
                                    return false;
                                }
                            }
                            else
                            {
                                if (Run_CreateArchive_TAR_AddFile(Flags, pData, TarArchive, RelFN, SourceList, null, pProgressForm) == -1)
                                {
                                    DestStream.Close(); DestStream.Dispose();
                                    DestList.CopyMode_CloseStreamForWrite(DestStream_File, true);
                                    return false;
                                }
                            }
                        }
                        TarArchive.EndArchive();
                    }

                    DestStream.Close(); DestStream.Dispose();
                    DestList.CopyMode_CloseStreamForWrite(DestStream_File, false);
                }
            }
            return true; // OK
        }
        /// <summary>Zaradenie priecinku do archivu</summary>
        /// <param name="pData">data</param>
        /// <param name="pArchive">objekt archivu</param>
        /// <param name="pName">nazov priecinku</param>
        /// <param name="pSource">zdrojovy zoznam</param>
        /// <param name="pNodeInfo">informacia o priecinku</param>
        /// <param name="pProgressForm">progress formular</param>
        /// <returns>0 - OK, 1 - preskocene, -1 prerusenie</returns>
        public static int Run_CreateArchive_TAR_AddDir(IConfirmationFlags pFlags, ICompressionDataStr pData, ITARArchiveCreator pArchive, string pName, INodeList pSource, INode pNodeInfo = null, IFileExplorer_ProgressForm_CompressItems pProgressForm = null)
        {
            DateTime DModify = pNodeInfo == null ? pSource.CopyMode_GetModifyDate(pName) : pNodeInfo.DLastModify;
            while (true)
            {
                if (pArchive.AddDir(pName, DModify) == 0) break; // Vytvorim priecinok
                if (pProgressForm != null)
                {
                    if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_13_1, pData.DestinationArchiveName), lang.FILE_EXPLORER_TEXT_39_13_2, lang.FILE_EXPLORER_TEXT_39_13_3, ref pFlags.CreateDestinationFileError)) return -1;
                }
            }
            if (pProgressForm != null) pProgressForm.AddDir();

            INodeList L = pSource.CopyMode_CreateSourceList(pName);
            if (L == null) return 1;

            bool IsFolder;
            using (INode N = new INode())
            {
                using (L)
                {
                    if (L.BeginExpand() == 0)
                    {
                        while (true)
                        {
                            N.Clear();
                            if (L.ExpandNext(null, N) != 1) break;

                            if (pProgressForm != null)
                            {
                                if (pProgressForm.WaitForTerminate.BoolValue) return -1; // Test ukoncenia
                            }

                            if ((pProgressForm != null) && (pProgressForm.WaitForTerminate.BoolValue)) return -1;

                            string RelFN = pSource.CopyMode_MakeRelative(IFileSystem.AppendToPath(L.CurrentPath, N.Name), out IsFolder, N.IsDirectory); // Ziskam relativnu cestu
                            if (RelFN != "") // Je platna?
                            {
                                if (IsFolder)
                                {
                                    if (Run_CreateArchive_TAR_AddDir(pFlags, pData, pArchive, RelFN, pSource, N, pProgressForm) == -1) return -1;
                                }
                                else
                                {
                                    if (Run_CreateArchive_TAR_AddFile(pFlags, pData, pArchive, RelFN, pSource, N, pProgressForm) == -1) return -1;
                                }
                            }
                        }
                        L.CloseExpand();
                    }
                }
            }
            return 0; // Vsetko OK
        }
        /// <summary>Zaradenie priecinku do archivu</summary>
        /// <param name="pData">data</param>
        /// <param name="pArchive">objekt archivu</param>
        /// <param name="pName">nazov priecinku</param>
        /// <param name="pSource">zdrojovy zoznam</param>
        /// <param name="pNodeInfo">informacia o priecinku</param>
        /// <param name="pProgressForm">progress formular</param>
        /// <returns>0 - OK, 1 - preskocene, -1 prerusenie</returns>
        public static int Run_CreateArchive_TAR_AddFile(IConfirmationFlags pFlags, ICompressionDataStr pData, ITARArchiveCreator pArchive, string pName, INodeList pSource, INode pNodeInfo = null, IFileExplorer_ProgressForm_CompressItems pProgressForm = null)
        {
            byte[] Buffer = new byte[MAX_COPY_BUFFER_SIZE];

            DateTime DModify = pNodeInfo == null ? pSource.CopyMode_GetModifyDate(pName) : pNodeInfo.DLastModify; // Ziskam datum modifikacie
            long Size = pNodeInfo == null ? pSource.CopyMode_GetSize(pName) : pNodeInfo.Size; // Ziskam dlzku

            if (Size > 0) // Subor ma nenulovu dlzku?
            {
                int R;
                while (true)
                {
                    R = pSource.CopyMode_OpenReadFile(pName, null); // Otvorim zdrojovy subor
                    if (R == 0) break;
                    switch (R)
                    {
                        default:
                            {
                                if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_7_1, pSource.CopyMode_MakeSourceFullPath(pName)), lang.FILE_EXPLORER_TEXT_39_7_2, lang.FILE_EXPLORER_TEXT_39_7_3, ref pFlags.OpenSourceFileError)) return -1;
                            } break;
                    }
                }
            }

            if (pProgressForm != null) pProgressForm.SetCurrentFileSize(Size, pSource.CopyMode_MakeSourceFullPath(pName));

            while (true)
            {
                if (pArchive.AddFile(pName, DModify, Size) == 0) break; // Vytvorim priecinok
                if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_13_1, pData.DestinationArchiveName), lang.FILE_EXPLORER_TEXT_39_13_2, lang.FILE_EXPLORER_TEXT_39_13_3, ref pFlags.CreateDestinationFileError)) return -1;
            }

            if (Size > 0)
            {
                int C;
                while (true)
                {
                    if ((pProgressForm != null) && (pProgressForm.WaitForTerminate.BoolValue)) return -1;
                    while (true)
                    {
                        C = pSource.CopyMode_ReadFile(Buffer.Length, Buffer);
                        if (C >= 0) break; // OK?
                        if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_39_12_1, pSource.CopyMode_MakeSourceFullPath(pName)), lang.FILE_EXPLORER_TEXT_39_12_2, lang.FILE_EXPLORER_TEXT_39_12_3, ref pFlags.ReadSourceFileError)) return -1;
                    }

                    if (C == 0) break; // Koniec citania?
                    pArchive.WriteFileData(Buffer, C);
                    if (pProgressForm != null) pProgressForm.AddTransferredDataSize(C);
                }
                pArchive.FinishFile();
            }

            pSource.CopyMode_CloseReadFile();
            if (pProgressForm != null)
            {
                pProgressForm.AddTransferredDataSize(0);
                pProgressForm.AddFile(false);
            }


            return 0; // Vsetko OK
        }
    }

    /// <summary>Trieda ITARArchiveCreator</summary>
    public class ITARArchiveCreator : IDisposable
    {
        protected System.IO.Stream FStream; // Stream archivu
        protected byte[] FBuffer; // Buffer
        protected readonly DateTime FStartDate = new DateTime(1970, 1, 1, 0, 0, 0);
        protected long FCurrentFileWriterBytes;

        /// <summary>Vyplnenie bufra nulami</summary>
        protected void ZeroBuffer()
        {
            for (int i = 0; i < 512; i++) FBuffer[i] = 0;
        }

        /// <summary>Zarovnanie retazca zlava znakom na pozadovanu dlzku</summary>
        /// <param name="pValue">vstup</param>
        /// <param name="pLength">dlzka</param>
        /// <param name="pChar">znak</param>
        /// <returns>vysledok</returns>
        protected string RoundString(string pValue, int pLength, char pChar)
        {
            if (pValue.Length == pLength) return pValue; // Rovnaka dlzka?
            if (pValue.Length > pLength) return pValue.Substring(pValue.Length - pLength); // Znizim pocet znakov

            System.Text.StringBuilder B = new System.Text.StringBuilder();
            for (int i = 0; i < pLength - pValue.Length; i++) B.Append(pChar);
            B.Append(pValue);
            return B.ToString();
        }

        /// <summary>Formatovanie modu suboru</summary>
        /// <param name="pValue">hodnota</param>
        /// <returns>vysledok</returns>
        protected string FormatMode(uint pValue)
        {
            string S = System.Convert.ToString(pValue, 8);
            return RoundString(S, 6, '0') + " " + (char)0;
        }
        /// <summary>Formatovanie velkosti suboru</summary>
        /// <param name="pValue">hodnota</param>
        /// <returns>vysledok</returns>
        protected string FormatSize(long pValue)
        {
            long L = 1 << 33;
            if (pValue < L)
            {
                string S = System.Convert.ToString(pValue, 8);
                return RoundString(S, 11, '0') + (char)0;
            }
            else return null;
        }
        /// <summary>Formatovanie datumu</summary>
        /// <param name="pValue">hodnota</param>
        /// <returns>vysledok</returns>
        protected string FormatDateTime(DateTime pValue)
        {
            string S = Convert.ToString((long)(pValue.ToUniversalTime().Subtract(FStartDate)).TotalSeconds, 8);
            return RoundString(S, 11, '0') + (char)0;
        }
        /// <summary>Formatovanie CRC</summary>
        /// <param name="pValue">hodnota</param>
        /// <returns>vysledok</returns>
        protected string FormatCRC(uint pValue)
        {
            return RoundString(Convert.ToString(pValue, 8), 7, '0') + (char)0;
        }

        /// <summary>Konstruktor</summary>
        /// <param name="pStream">stream</param>
        public ITARArchiveCreator(System.IO.Stream pStream)
        {
            FStream = pStream;
            FBuffer = new byte[512];
        }
        /// <summary>Dispose metoda</summary>
        public void Dispose()
        {
        }

        /// <summary>Zaradenie priecinku</summary>
        /// <param name="pName">nazov</param>
        /// <param name="pModifyTime">datum modifikacie</param>
        /// <returns>0 alebo kod chyby</returns>
        public int AddDir(string pName, DateTime pModifyTime)
        {
            ZeroBuffer(); // Vynulujem buffer

            string N = pName.Replace('\\', '/') + "/"; // Vytvorim platny nazov
            byte[] NameBytes = System.Text.Encoding.Default.GetBytes(N); // Ziskam bajty
            if (NameBytes.Length < 100)
            {
                NameBytes.CopyTo(FBuffer, 0); // Nazov
                System.Text.Encoding.ASCII.GetBytes(FormatMode(0x1ed)).CopyTo(FBuffer, 100); // Mod
                System.Text.Encoding.ASCII.GetBytes(FormatSize(0)).CopyTo(FBuffer, 124); // Dlzka
                System.Text.Encoding.ASCII.GetBytes(FormatDateTime(pModifyTime)).CopyTo(FBuffer, 136); // Cas
                System.Text.Encoding.ASCII.GetBytes("ustar ").CopyTo(FBuffer, 257); // "ustar"

                System.Text.Encoding.ASCII.GetBytes(FormatCRC(INodeList_TAR.CalculateCRC(FBuffer, 512))).CopyTo(FBuffer, 148); // Vypocet CRC
                FStream.Write(FBuffer, 0, 512);
            }
            else
            {
                System.Text.Encoding.ASCII.GetBytes("././@LongLink").CopyTo(FBuffer, 0); // Nazov
                System.Text.Encoding.ASCII.GetBytes(FormatMode(0x1ed)).CopyTo(FBuffer, 100); // Mod
                System.Text.Encoding.ASCII.GetBytes(FormatSize(0)).CopyTo(FBuffer, 124); // Dlzka
                System.Text.Encoding.ASCII.GetBytes(FormatDateTime(pModifyTime)).CopyTo(FBuffer, 136); // Cas
                System.Text.Encoding.ASCII.GetBytes("ustar ").CopyTo(FBuffer, 257); // "ustar"
                FBuffer[156] = (byte)'L';

                System.Text.Encoding.ASCII.GetBytes(FormatCRC(INodeList_TAR.CalculateCRC(FBuffer, 512))).CopyTo(FBuffer, 148); // Vypocet CRC
                FStream.Write(FBuffer, 0, 512);

                ZeroBuffer(); // Vynulujem buffer
                NameBytes.CopyTo(FBuffer, 0); // Nazov
                FStream.Write(FBuffer, 0, 512);

                ZeroBuffer(); // Vynulujem buffer
                for (int i = 0; i < 100; i++) FBuffer[i] = NameBytes[i]; // Skopirujem cast nazvu
                System.Text.Encoding.ASCII.GetBytes(FormatMode(0x1ed)).CopyTo(FBuffer, 100); // Mod
                System.Text.Encoding.ASCII.GetBytes(FormatSize(0)).CopyTo(FBuffer, 124); // Dlzka
                System.Text.Encoding.ASCII.GetBytes(FormatDateTime(pModifyTime)).CopyTo(FBuffer, 136); // Cas
                System.Text.Encoding.ASCII.GetBytes("ustar ").CopyTo(FBuffer, 257); // "ustar"

                System.Text.Encoding.ASCII.GetBytes(FormatCRC(INodeList_TAR.CalculateCRC(FBuffer, 512))).CopyTo(FBuffer, 148); // Vypocet CRC
                FStream.Write(FBuffer, 0, 512);
            }


            return 0;
        }
        /// <summary>Zaradenie suboru</summary>
        /// <param name="pName">nazov</param>
        /// <param name="pModifyTime">datum modifikacie</param>
        /// <param name="pSize">dlzka</param>
        /// <returns>0 alebo kod chyby</returns>
        public int AddFile(string pName, DateTime pModifyTime, long pSize)
        {
            ZeroBuffer(); // Vynulujem buffer

            string N = pName.Replace('\\', '/'); // Vytvorim platny nazov
            byte[] NameBytes = System.Text.Encoding.Default.GetBytes(N); // Ziskam bajty
            if (NameBytes.Length < 100)
            {
                NameBytes.CopyTo(FBuffer, 0); // Nazov
                System.Text.Encoding.ASCII.GetBytes(FormatMode(0x1a4)).CopyTo(FBuffer, 100); // Mod
                string S = FormatSize(pSize);
                if (S != null) System.Text.Encoding.ASCII.GetBytes(S).CopyTo(FBuffer, 124); // Dlzka
                else
                {
                    FBuffer[124] = 0x80;
                    BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(pSize)).CopyTo(FBuffer, 128);
                }
                System.Text.Encoding.ASCII.GetBytes(FormatDateTime(pModifyTime)).CopyTo(FBuffer, 136); // Cas
                System.Text.Encoding.ASCII.GetBytes("ustar ").CopyTo(FBuffer, 257); // "ustar"

                System.Text.Encoding.ASCII.GetBytes(FormatCRC(INodeList_TAR.CalculateCRC(FBuffer, 512))).CopyTo(FBuffer, 148); // Vypocet CRC
                FStream.Write(FBuffer, 0, 512);
            }
            else
            {
                System.Text.Encoding.ASCII.GetBytes("././@LongLink").CopyTo(FBuffer, 0); // Nazov
                System.Text.Encoding.ASCII.GetBytes(FormatMode(0x1a4)).CopyTo(FBuffer, 100); // Mod
                string S = FormatSize(pSize);
                if (S != null) System.Text.Encoding.ASCII.GetBytes(S).CopyTo(FBuffer, 124); // Dlzka
                else
                {
                    FBuffer[124] = 0x80;
                    BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(pSize)).CopyTo(FBuffer, 128);
                }
                System.Text.Encoding.ASCII.GetBytes(FormatDateTime(pModifyTime)).CopyTo(FBuffer, 136); // Cas
                System.Text.Encoding.ASCII.GetBytes("ustar ").CopyTo(FBuffer, 257); // "ustar"
                FBuffer[156] = (byte)'L';

                System.Text.Encoding.ASCII.GetBytes(FormatCRC(INodeList_TAR.CalculateCRC(FBuffer, 512))).CopyTo(FBuffer, 148); // Vypocet CRC
                FStream.Write(FBuffer, 0, 512);

                ZeroBuffer(); // Vynulujem buffer
                NameBytes.CopyTo(FBuffer, 0); // Nazov
                FStream.Write(FBuffer, 0, 512);

                ZeroBuffer(); // Vynulujem buffer
                for (int i = 0; i < 100; i++) FBuffer[i] = NameBytes[i]; // Skopirujem cast nazvu
                System.Text.Encoding.ASCII.GetBytes(FormatMode(0x1a4)).CopyTo(FBuffer, 100); // Mod
                S = FormatSize(pSize);
                if (S != null) System.Text.Encoding.ASCII.GetBytes(S).CopyTo(FBuffer, 124); // Dlzka
                else
                {
                    FBuffer[124] = 0x80;
                    BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(pSize)).CopyTo(FBuffer, 128);
                }
                System.Text.Encoding.ASCII.GetBytes(FormatDateTime(pModifyTime)).CopyTo(FBuffer, 136); // Cas
                System.Text.Encoding.ASCII.GetBytes("ustar ").CopyTo(FBuffer, 257); // "ustar"

                System.Text.Encoding.ASCII.GetBytes(FormatCRC(INodeList_TAR.CalculateCRC(FBuffer, 512))).CopyTo(FBuffer, 148); // Vypocet CRC
                FStream.Write(FBuffer, 0, 512);
            }

            FCurrentFileWriterBytes = 0;
            return 0;
        }
        /// <summary>Zapis dat do archivu</summary>
        /// <param name="pBuffer">buffer</param>
        /// <param name="pLength">dlzka</param>
        /// <returns>pocet zapisanych bajtov alebo kod chyby</returns>
        public int WriteFileData(byte[] pBuffer, int pLength)
        {
            try
            {
                FStream.Write(pBuffer, 0, pLength);
                FCurrentFileWriterBytes += pLength;
                return pLength;
            }
            catch
            {
                return IFileSystem.FS_ERROR_UNKNOWN;
            }
        }
        /// <summary>Ukoncenie zapisu suboru</summary>
        /// <returns>0 alebo kod chyby</returns>
        public int FinishFile()
        {
            long L = (FCurrentFileWriterBytes & (~511)) + 512;
            int C = (int)(L - FCurrentFileWriterBytes);
            if ((C == 512) || (C == 0)) return 0; // Ziadne zarovnanie nebude
            
            ZeroBuffer(); // Vymazem buffer
            try
            {
                FStream.Write(FBuffer, 0, C); // Zarovnam na 512 bajtov
                return 0;
            }
            catch
            {
                return IFileSystem.FS_ERROR_UNKNOWN;
            }

        }

        /// <summary>Ukoncenie archivu</summary>
        /// <returns>0 alebo kod chyby</returns>
        public int EndArchive()
        {
            ZeroBuffer();
            try
            {
                FStream.Write(FBuffer, 0, 512); // Zapisem prazdny blok
                return 0;
            }
            catch
            {
                return IFileSystem.FS_ERROR_UNKNOWN;
            }
        }
    }
}
